﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.IO;
using UCore;

namespace Twin {
    public partial class frmOled : Form
    {
        private const int SquareSize = 8;
        private const int Spacing = 0;      //1;
        private const int ScreenWidth = 128;
        private const int ScreenHeight = 64;

        private int margin = 150;
        //private int x_offset;
        //private int y_offset;

        //private List<string> lastLines;

        char[,] map = new char[ScreenHeight, ScreenWidth]; //new char[64, 128];

        //arg[]
        private string[] arg;
        //
        private int INST_BITS = 0;
        private int INST_OP = 1;
        private int INST_CMFG = 2;
        private int INST_I_BTN = 3;

        //square
        private char OFF = '1';
        private char ON = '0';

        //btn
        private int BTN_FUN = 0;
        private int BTN_NEXT = 1;
        private int BTN_CONNECT = 2;


        private XPort xport = new XPort();

        public static Oled oled;



        //=====================================================================================

        //hexGRAM -> map[i, j]
        private void convertToMap(string hexGRAM) {
            try {
                // Clear the map first
                for (int i = 0; i < ScreenHeight; i++) {
                    for (int j = 0; j < ScreenWidth; j++) {
                        map[i, j] = OFF;  // Initialize to 'off' state
                    }
                }

                // Convert hex string to byte array
                byte[] b = Common.Hex2Array(hexGRAM);

                // Each byte represents 8 vertical pixels (1 bit per pixel)
                // OLED is organized in pages (8 pixel tall rows)
                for (int page = 0; page < 8; page++) {  // 8 pages (64/8)
                    for (int col = 0; col < ScreenWidth; col++) {
                        int byteIndex = page * ScreenWidth + col;
                        if (byteIndex >= b.Length) continue;

                        byte currentByte = b[byteIndex];
                        for (int bit = 0; bit < 8; bit++) {
                            int y = page * 8 + bit;
                            if (y >= ScreenHeight) continue;

                            // Check if bit is set
                            if ((currentByte & (1 << bit)) != 0) {
                                map[y, col] = ON;  // Pixel on
                            } else {
                                map[y, col] = OFF;  // Pixel off
                            }
                        }
                    }
                }
            } catch (Exception ex) {
                Console.WriteLine("Error converting hexGRAM to map: " + ex.Message);
            }
        }


        //刷新数据
        private void UpdateUI(string hexGRAM) {
            try {
                // Update the map data
                convertToMap(hexGRAM);

                // Trigger a repaint
                this.Invalidate();
            } catch (Exception ex) {
                Console.WriteLine("Error updating UI: " + ex.Message);
            }
        }


        //事件
        private void Oled_DataReceived(object sender, DataReceivedEventArgs e) {
            // 确保在 UI 线程上更新
            if (this.InvokeRequired) {
                this.Invoke(new Action(() => UpdateUI(e.Data)));
            } else {
                UpdateUI(e.Data);
            }
        }

        
        protected override void OnPaint(PaintEventArgs e) {
            base.OnPaint(e);
            oled_RefreshMap(e);
        }


        public frmOled(XPort xport, string content)
        {
            InitializeComponent();

            // Initialize map with all pixels off
            for (int i = 0; i < ScreenHeight; i++) {
                for (int j = 0; j < ScreenWidth; j++) {
                    map[i, j] = OFF;
                }
            }

            //订阅数据
            oled = new Oled();
            oled.DataReceived += Oled_DataReceived;

            this.xport = xport;

            //para: [cmfg], 1[i_btn]
            arg = content.Split(',');

            arg[INST_OP] = Common.RemoveBracketedContent(arg[INST_OP]);
            arg[INST_CMFG] = Common.RemoveBracketedContent(arg[INST_CMFG]);
            arg[INST_I_BTN] = Common.RemoveBracketedContent(arg[INST_I_BTN]);
        }


        private void Oled_Load(object sender, EventArgs e) {
            this.DoubleBuffered = true;

            // Calculate total display area (including 2 square size padding around the display)
            int displayAreaWidth = ScreenWidth * (SquareSize + Spacing) + 4 * SquareSize;
            int displayAreaHeight = ScreenHeight * (SquareSize + Spacing) + 4 * SquareSize;

            // Set form size to accommodate display area with margins
            this.Width = displayAreaWidth + margin * 2;
            this.Height = displayAreaHeight + margin;

            // Center the form on screen (optional)
            this.StartPosition = FormStartPosition.CenterScreen;
        }


        private void oled_RefreshMap(PaintEventArgs e) {
            Brush brush;
            Graphics g = e.Graphics;

            // Clear background
            g.Clear(this.BackColor);

            // Scaling factor (1.0 = 100%, 0.75 = 75%, 0.5 = 50%, 0.25 = 25%)
            float scaleFactor = 0.25f; // Change this value as needed (0.75f, 0.5f, or 0.25f)

            // Calculate scaled sizes
            int scaledSquareSize = (int)(SquareSize * scaleFactor);
            int scaledSpacing = (int)(Spacing * scaleFactor);

            // Calculate total display area size (display + 2 square padding)
            int displayAreaWidth = (int)((ScreenWidth * (SquareSize + Spacing) + 4 * SquareSize) * scaleFactor);
            int displayAreaHeight = (int)((ScreenHeight * (SquareSize + Spacing) + 4 * SquareSize) * scaleFactor);

            // Calculate centered position
            int bgX = (this.ClientSize.Width - displayAreaWidth) / 2;
            int bgY = (this.ClientSize.Height - displayAreaHeight) / 2;

            // Draw gray background (centered)
            g.FillRectangle(Brushes.Gray, bgX, bgY, displayAreaWidth, displayAreaHeight);

            // Calculate starting position for pixels (inside the gray background)
            int pixelStartX = bgX + (int)(2 * SquareSize * scaleFactor);
            int pixelStartY = bgY + (int)(2 * SquareSize * scaleFactor);

            // Draw OLED pixels
            for (int y = 0; y < ScreenHeight; y++) {
                for (int x = 0; x < ScreenWidth; x++) {
                    int pixelX = pixelStartX + x * (scaledSquareSize + scaledSpacing);
                    int pixelY = pixelStartY + y * (scaledSquareSize + scaledSpacing);

                    brush = (map[y, x] == OFF) ? Brushes.Black : Brushes.White;
                    g.FillRectangle(brush, pixelX, pixelY, scaledSquareSize, scaledSquareSize);
                }
            }
        }


        private void btnQuit_Click(object sender, EventArgs e) {
            this.Close();
        }


        private void sendBtn(int iBtn) {
            CInfo cInfo = new CInfo();

            Msg.setInfo_bits(ref cInfo, arg[INST_BITS]);
            arg[INST_I_BTN] = iBtn.ToString();
            string opargs = arg[INST_OP] + "," + arg[INST_CMFG] + "," + arg[INST_I_BTN];

            cInfo.sOpArgs = opargs;
            TConsole.sendAsProtocol(xport, ref cInfo, "", "cobra");
        }


        private void btnFun_Click(object sender, EventArgs e) {
            sendBtn(BTN_FUN);
        }


        private void btnNext_Click(object sender, EventArgs e) {
            sendBtn(BTN_NEXT);
        }

        private void btnConnect_Click(object sender, EventArgs e) {
            // 清空显示区
            for (int i = 0; i < ScreenHeight; i++) {
                for (int j = 0; j < ScreenWidth; j++) {
                    map[i, j] = OFF; // 将像素状态设为关闭
                }
            }
            this.Invalidate(); // 立即触发界面重绘
            //
            sendBtn(BTN_CONNECT);
        }
    }
}
